package com.amiu.autoMybatis;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import sun.tools.tree.ThisExpression;

import com.alibaba.druid.pool.DruidDataSource;
import com.amiu.autoMybatis.annotation.Mapper;
import com.amiu.autoMybatis.test.mapper.DaoMapper;
import com.amiu.util.PackageUtil;

public class MybatisInitialization {
	//临时用
	String propsDriverKey="db.driver";
	String propsUrlKey ="db.shiro_test.url";
	String propsUsernameKey="db.username";
	String propsPasswordKey="db.password";
	
	/**
	 * propertiesReader应变为1个类 sqlSession应变为一个类，处理事务，和close()
	 * */

	// 默认扫描整个项目，用junit@Test会出错，不会扫描整个项目
	// 详见packagePath2FilePath()中的url.path()
	private String baseScanPackage = "";
	private SqlSessionFactory sqlSessionFactory;
	// 注解，标记我们的mapper类的注解
	private Class<?> scanAnnotation = Mapper.class;
	private String CLASSPATH_PREFIX="classpath:";
	private String resourcePath="";
	
	public String getResourcePath() {
		return resourcePath;
	}

	public void setResourcePath(String resourcePath) {
		this.resourcePath = resourcePath;
	}

	public MybatisInitialization() {
	}

	public MybatisInitialization(Class<?> annotationClazz) {
		this.scanAnnotation = annotationClazz;
	}

	public void setBaseScanPackage(String baseScanPackage) {
		this.baseScanPackage = baseScanPackage;
	}

	public SqlSessionFactory getSqlSessionFactory() {
		if (sqlSessionFactory == null) {
			try {
				sqlSessionFactory = load(resourcePath);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sqlSessionFactory;
	}

	public void setAnnotationClazz(Class<?> annotationClazz) {
		this.scanAnnotation = annotationClazz;
	}

	SqlSessionFactory load(String resourcePath) throws Exception {
		
		Properties props=null;
		if (resourcePath.startsWith(CLASSPATH_PREFIX)) {
			props = propertiesClasspathReader(resourcePath);
		}else{
			props = defaultPropertiesReader();
//			props = propertiesReader("com.amiu.autoMybatis",
//				"dbConfig.properties");
		}
		
		String driver = props.getProperty(propsDriverKey);
		// String url = props.getProperty("duobaowithoneyuan.url");
		String url = props.getProperty(propsUrlKey);
		String username = props.getProperty(propsUsernameKey);
		String password = props.getProperty(propsPasswordKey);

		// 获取DataSource，DataSource接口有多个实现类，我们用的是mybatis给我们提供的PooledDataSource
		PooledDataSource pooledDataSource = new PooledDataSource(driver, url,
				username, password);
		// 若需要配置pooledDatasource，则可以用他的set方法，如
		pooledDataSource.setLoginTimeout(6000);

		DruidDataSource druidDataSource = new DruidDataSource();
		druidDataSource.setDriverClassName(driver);
		druidDataSource.setUrl(url);
		druidDataSource.setUsername(username);
		druidDataSource.setPassword(password);

		// 可以选择不同的DataSource，我们上面配置了两个dataSource
		// DataSource dataSource = pooledDataSource;
		DataSource dataSource = druidDataSource;

		// 配置事务管理，这里我们使用JDBC的事务
		TransactionFactory trcFactory = new JdbcTransactionFactory();

		// 配置Environment对象，"development"是我们给起的名字
		Environment env = new Environment("development", trcFactory, dataSource);
		// 创建Configuration对象
		Configuration config = new Configuration(env);
		// <settings></settings>中的内容在此处配置
		// config.setLazyLoadingEnabled(true);

		// 扫描baseScanPackage，添加mapper
		List<Class<?>> mapperClazzList = scanDaoMapper(baseScanPackage);
		for (Class<?> mapperClazz : mapperClazzList) {
			// 添加映射接口，若有xml文件，则xml的文件应和接口文件同名
			config.addMapper(mapperClazz);
		}

		SqlSessionFactory ssFactory = new SqlSessionFactoryBuilder()
				.build(config);
		return ssFactory;
	}

	private Properties propertiesFilePathReader(String packagePath, String fileName)
			throws IOException, FileNotFoundException {
		String filePath = packagePath2FilePath(packagePath);
		Properties props = new Properties();
		props.load(new FileInputStream(filePath + File.separator + fileName));
		return props;
	}

	//默认扫描本包
	public Properties defaultPropertiesReader()
			throws IOException, FileNotFoundException {
		URL url = MybatisInitialization.class.getResource("/");
		String currentpath = url.getPath();
		Properties props = new Properties();
		props.load(new FileInputStream(currentpath + File.separator + "dbConfig.properties"));
		return props;
	}
	
	public Properties propertiesClasspathReader(String classPathName)
			throws IOException, FileNotFoundException {
		Properties props = new Properties();
		String fileName = classPathName.substring(classPathName.indexOf(":")+1);
		InputStream is = MybatisInitialization.class.getResourceAsStream(fileName);
		props.load(is);
		return props;
	}

	// 包路径转换为文件绝对路径
	private String packagePath2FilePath(String packagePath) {
		
		String filePath = packagePath.replace(".", "/");
		// 包路径
		return toAbsolutePath(filePath);
	}
	//获取当前资源绝对路径
	private String toAbsolutePath(String filePath) {
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		URL url = loader.getResource(filePath);
		return url.getPath();
	}

	/**
	 * 扫描mybatis Mapper.class
	 * 
	 * @param basePackage
	 * @return
	 * @throws Exception
	 */
	private List<Class<?>> scanDaoMapper(String basePackage) throws Exception {
		List<Class<?>> anntationClazz = new ArrayList<Class<?>>();
		List<String> classOfString = PackageUtil
				.getClassName(basePackage, true);
		for (String className : classOfString) {
			// 不处理内部类，内部类className型如ClassA&ClassB
			if (!className.contains("&")) {
				Class<?> clazz = Class.forName(className);
				// 只处理接口，我们使用mybatis时，Mapper全是接口
				if (clazz.isInterface() && isMarkClass(clazz)) {
					anntationClazz.add(clazz);
				}
			}
		}
		return anntationClazz;
	}

	/**
	 * 这个类是否是我们标记注解scanAnnotation的类
	 * 
	 * @param clazz
	 * @return
	 * @throws Exception
	 */
	private boolean isMarkClass(Class<?> clazz) throws Exception {
		for (Annotation annotation : clazz.getAnnotations()) {
			if (scanAnnotation == null)
				throw new Exception("请添加需扫描的注解");
			if (annotation.annotationType() == scanAnnotation) {
				return true;
			}
		}
		return false;
	}

	public static void main(String[] args) throws FileNotFoundException {
		MybatisInitialization init = new MybatisInitialization(Mapper.class);
		//init.setResourcePath("classpath:dbConfig.properties");
		// 可以不设置基础扫描包，默认扫描整个项目
		init.setBaseScanPackage("com.amiu.autoMybatis.mapper");
//		SqlSessionFactory sqlSessionFactory = init.getSqlSessionFactory();
//		SqlSession sqlSession = sqlSessionFactory.openSession();
//		DaoMapper dao = sqlSession.getMapper(DaoMapper.class);
//		System.out.println(dao.findById(1).getName());
//		System.out.println(init.toAbsolutePath("com/amiu"));
		
		try {
			Properties p = init.defaultPropertiesReader();
			System.out.println(p.getProperty("password"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// SqlSessionHelper sqlSession =
		// new SqlSessionHelper(init.getSqlSessionFactory());
		// DaoInterface dao = sqlSession.getDao(DaoInterface.class);
		// System.out.println(dao.findById(1).getName());
		
//		ClassLoader loader = Thread.currentThread().getContextClassLoader();
//		URL url = loader.getResource("");
//		System.out.println(url.getPath());
//		String path = "classpath:abc";
//		System.out.println(path.substring(path.indexOf(":") + 1));
//		InputStream is = 
//				MybatisInitialization.class.
//					getClassLoader().getResourceAsStream("dbConfig.properties");
//		System.out.println(MybatisInitialization.class.getResource("/"));
//		Properties props = new Properties();
//		try {
//			props.load(is);
//		} catch (IOException e) {
//			System.out.println("properties no found");
//			e.printStackTrace();
//		}
//		System.out.println(props.getProperty("password"));
	}

	public String currentPackageName(Class<?> clazz) {
		return clazz.getPackage().getName();
	}

}
